// RectWindow.cpp
// by Charles Mc Auley
// "Programming AutoCAD 2000 with ObjectARX"


#include "StdArx.h"
#include "string.h" // strcpy

ACRX_DXF_DEFINE_MEMBERS(RectWindow, AcDbObject,
                        AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
                        AcDbProxyObject::kNoOperation,
                        WINDO_INFO, Ch8_4
);

MAKE_ACDBOPENOBJECT_FUNCTION(RectWindow);

RectWindow::RectWindow()
{
	// Initialize the rect Frame Thickness
	// and the internal Window Framing thickness

	m_nrows = 1;
	m_ncols = 1;
	m_drectFrameLen = 0.0;
	m_drectFrameHt	 = 0.0;

	strcpy(m_strWindType, "Rect");

	m_lowLeftPt.set(0.0, 0.00);
}

RectWindow::~RectWindow()
{
	// Does nothing
}


void RectWindow::drawWindow(AcDbBlockTableRecord* pBlkTableRecord)
{
	AcGePoint2dArray outrFrame;
	AcDbPolyline* pFrame;
	AcDbObjectId plineId;
	AcGeVector2d vec;
	AcGePoint2d ll, lr, ur, ul;
	AcGePoint2d vrtxPt;
	double len, ht;
	Acad::ErrorStatus es;

	// Get the window length, height and start point
	len = getWindowLength();
	ht	= getWindowHeight();
	ll	= getWindowStartPoint();

	// Calculate the other 3 corner points
	// from ll
	vec.set(len, 0);
	lr = ll + vec;
	vec.set(0, ht);
	ur = lr + vec;
	ul = ll + vec;

	// Add the four calculated points to the array
	outrFrame.append(ll);
	outrFrame.append(lr);
	outrFrame.append(ur);
	outrFrame.append(ul);

	pFrame = new AcDbPolyline(4);

	for(int count = 0; count < outrFrame.length(); count++)
	{
		vrtxPt = outrFrame.at(count);
		pFrame->addVertexAt(count, vrtxPt);
	}

	pFrame->setClosed(Adesk::kTrue);

	es = pBlkTableRecord->appendAcDbEntity(plineId, pFrame);
	if(es != Acad::eOk)
	{
		acutPrintf("\nError in drawing window frame. ");
		if(pFrame != NULL)
		{
			delete pFrame;
		}

		return;
	}

	pFrame->close();

	return;
}


// Get and Set functions

Adesk::Int32 RectWindow::getWindowRows() const
{
	return m_nrows;
}

Adesk::Int32 RectWindow::getWindowCols() const
{
	return m_ncols;
}

double RectWindow::getWindowHeight() const
{
	return m_drectFrameHt;
}

double RectWindow::getWindowLength() const
{
	return m_drectFrameLen;
}

AcGePoint2d RectWindow::getWindowStartPoint() const
{
	return m_lowLeftPt;
}


void RectWindow::setWindowRows(Adesk::Int32 rowQty)
{
	m_nrows = rowQty;
}

void RectWindow::setWindowCols(Adesk::Int32 colQty)
{
	m_ncols = colQty;
}

void RectWindow::setWindowHeight(double windHeight)
{
	m_drectFrameHt = windHeight;
}

void RectWindow::setWindowLength(double windLength)
{
	m_drectFrameLen = windLength;
}


void RectWindow::setWindowStartPoint(AcGePoint2d lowLeftPoint)
{
	m_lowLeftPt = lowLeftPoint;
}

void RectWindow::addWindowInfo(RectWindow *pWindowObj)
{
	AcDbDatabase *pCurDb;
    AcDbObject *pObj;
    AcDbObjectId dictObjId, entId, windowObjId;
    AcDbDictionary *pNamedObjD, *pDict;

	ads_name ename;

	AcDbHandle handEnt;

	char strHandle[17];

	pCurDb = acdbHostApplicationServices()->workingDatabase();

    pCurDb->getNamedObjectsDictionary(pNamedObjD, AcDb::kForWrite);

    // Check to see if the dictionary we want to create is
    // already present if it's not, then create it and add
    // it to the named object dictionary.
    // 
    if (pNamedObjD->getAt("WINDO_INFO", (AcDbObject*&) pDict,
        AcDb::kForWrite) == Acad::eKeyNotFound)
    {
        pDict = new AcDbDictionary;
        pNamedObjD->setAt("WINDO_INFO", pDict, dictObjId);
    }
    pNamedObjD->close();

	
	// Get the last entity
	acdbEntLast(ename);
	// Get the entity object ID
	acdbGetObjectId(entId, ename);

	// Open the enity for a read operation
	acdbOpenObject(pObj, entId, AcDb::kForRead);

	pObj->getAcDbHandle(handEnt);

	handEnt.getIntoAsciiBuffer(strHandle);

    pObj->close();

    pDict->setAt(strHandle, pWindowObj, windowObjId);

    pDict->close();
}

// AcDbObject persistence protocol follows

Acad::ErrorStatus RectWindow::dwgInFields(AcDbDwgFiler* pFiler)
{
	assertWriteEnabled();
	AcDbObject::dwgInFields(pFiler);

	char *pstrWindType = NULL;

	pFiler->readString(&pstrWindType);
	strcpy(m_strWindType, pstrWindType);
	pFiler->readItem(&m_ncols);
	pFiler->readItem(&m_nrows);
	pFiler->readItem(&m_drectFrameLen);
	pFiler->readItem(&m_drectFrameHt);
	pFiler->readItem(&m_lowLeftPt);

	if(pstrWindType != NULL)
	{
		delete pstrWindType;
	}

	return pFiler->filerStatus();
}

Acad::ErrorStatus RectWindow::dwgOutFields(AcDbDwgFiler* pFiler) const
{
	assertReadEnabled();
	AcDbObject::dwgOutFields(pFiler);

	pFiler->writeItem(m_strWindType);
	pFiler->writeItem(getWindowCols());
	pFiler->writeItem(getWindowRows());
	pFiler->writeItem(getWindowLength());
	pFiler->writeItem(getWindowHeight());
	pFiler->writeItem(getWindowStartPoint());

	return pFiler->filerStatus();
}


// Files data in from a DXF file
//
Acad::ErrorStatus RectWindow::dxfInFields(AcDbDxfFiler* pFiler)
{
	struct resbuf rb;
	AcGePoint2d llpt;

	assertWriteEnabled();

	Acad::ErrorStatus es;
	if ((es = AcDbObject::dxfInFields(pFiler))
		!= Acad::eOk)
	{
		acutPrintf("\nError in DXFIN ");
		return es;
	}

	// Check if we're at the right subclass getData marker
	//
	if (!pFiler->atSubclassData("Windo_Info"))
	{
		acutPrintf("\nBad DXFIN subclass marker ");
		return Acad::eBadDxfSequence;
	}

	pFiler->readItem(&rb);
	if(rb.restype == AcDb::kDxfXTextString)
	{
		strcpy(m_strWindType, rb.resval.rstring);
	}
	else
	{
		pFiler->pushBackItem();

		pFiler->setError(Acad::eInvalidDxfCode,
			"\nError: expected group code %d",
			AcDb::kDxfXTextString);

		return pFiler->filerStatus();
	}

	pFiler->readItem(&rb);
	if(rb.restype == AcDb::kDxfInt32)
	{
		setWindowCols(rb.resval.rlong);
	}
	else
	{
		pFiler->pushBackItem();

		pFiler->setError(Acad::eInvalidDxfCode,
			"\nError: expected group code %d",
			AcDb::kDxfInt32);

		return pFiler->filerStatus();
	}

	pFiler->readItem(&rb);
	if(rb.restype == AcDb::kDxfInt32)
	{
		setWindowRows(rb.resval.rlong);
	}
	else
	{
		pFiler->pushBackItem();

		pFiler->setError(Acad::eInvalidDxfCode,
			"\nError: expected group code %d",
			AcDb::kDxfInt32);

		return pFiler->filerStatus();
	}

	pFiler->readItem(&rb);
	if(rb.restype == AcDb::kDxfReal)
	{
		setWindowLength(rb.resval.rreal);
	}
	else
	{
		pFiler->pushBackItem();

		pFiler->setError(Acad::eInvalidDxfCode,
			"\nError: expected group code %d",
			AcDb::kDxfReal);

		return pFiler->filerStatus();
	}

	pFiler->readItem(&rb);
	if(rb.restype == AcDb::kDxfReal)
	{
		setWindowHeight(rb.resval.rreal);
	}
	else
	{
		pFiler->pushBackItem();

		pFiler->setError(Acad::eInvalidDxfCode,
			"\nError: expected group code %d",
			AcDb::kDxfReal);

		return pFiler->filerStatus();
	}

	pFiler->readItem(&rb);
	if(rb.restype == AcDb::kDxfXCoord)
	{
		llpt.x = rb.resval.rpoint[X];
		llpt.y = rb.resval.rpoint[Y];
		setWindowStartPoint(llpt);
	}
	else
	{
		pFiler->pushBackItem();

		pFiler->setError(Acad::eInvalidDxfCode,
			"\nError: expected group code %d",
			AcDb::kDxfXCoord);

		return pFiler->filerStatus();
	}


	return pFiler->filerStatus();
}

// Files data out to a DXF file
//
Acad::ErrorStatus RectWindow::dxfOutFields(AcDbDxfFiler* pFiler) const
{
    assertReadEnabled();

    AcDbObject::dxfOutFields(pFiler);

    pFiler->writeItem(AcDb::kDxfSubclass, "Windo_Info");
    pFiler->writeItem(AcDb::kDxfXTextString, m_strWindType);
	pFiler->writeItem(AcDb::kDxfInt32, getWindowCols());
	pFiler->writeItem(AcDb::kDxfInt32, getWindowRows());
	pFiler->writeItem(AcDb::kDxfReal, getWindowLength());
	pFiler->writeItem(AcDb::kDxfReal, getWindowHeight());
	pFiler->writeItem(AcDb::kDxfXCoord, getWindowStartPoint());

    return pFiler->filerStatus();
}